/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */
package xowl.interpreter.frontends.functional;

import java.io.Writer;
import java.util.List;
import xowl.lang.actions.Lambda;
import xowl.lang.owl2.AnonymousIndividual;
import xowl.lang.owl2.ClassExpression;
import xowl.lang.owl2.DataAllValuesFrom;
import xowl.lang.owl2.DataComplementOf;
import xowl.lang.owl2.DataExactCardinality;
import xowl.lang.owl2.DataHasValue;
import xowl.lang.owl2.DataIntersectionOf;
import xowl.lang.owl2.DataMaxCardinality;
import xowl.lang.owl2.DataMinCardinality;
import xowl.lang.owl2.DataOneOf;
import xowl.lang.owl2.DataPropertyExpression;
import xowl.lang.owl2.DataSomeValuesFrom;
import xowl.lang.owl2.DataUnionOf;
import xowl.lang.owl2.Datarange;
import xowl.lang.owl2.DatatypeRestriction;
import xowl.lang.owl2.IRI;
import xowl.lang.owl2.IndividualExpression;
import xowl.lang.owl2.Literal;
import xowl.lang.owl2.LiteralExpression;
import xowl.lang.owl2.ObjectAllValuesFrom;
import xowl.lang.owl2.ObjectComplementOf;
import xowl.lang.owl2.ObjectExactCardinality;
import xowl.lang.owl2.ObjectHasSelf;
import xowl.lang.owl2.ObjectHasValue;
import xowl.lang.owl2.ObjectIntersectionOf;
import xowl.lang.owl2.ObjectInverseOf;
import xowl.lang.owl2.ObjectMaxCardinality;
import xowl.lang.owl2.ObjectMinCardinality;
import xowl.lang.owl2.ObjectOneOf;
import xowl.lang.owl2.ObjectSomeValuesFrom;
import xowl.lang.owl2.ObjectUnionOf;

/**
 *
 * @author Laurent WOUTERS
 */
public class ExpressionWriter extends xowl.interpreter.frontends.AbstractStaticExpressionWriter {
    private FunctionalWriter parent;
    
    public ExpressionWriter(FunctionalWriter parent) {
        this.parent = parent;
    }
    
    @Override protected void writeEntity(Writer writer, IRI expression) throws java.io.IOException {
        writer.write(parent.toShortIRI(expression));
    }

    @Override protected void writeClass(Writer writer, IRI expression) throws java.io.IOException { writeEntity(writer, expression); }

    @Override protected void writeObjectUnionOf(Writer writer, ObjectUnionOf expression) throws java.io.IOException {
        List<ClassExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getClassSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectUnionOf);
        writer.write("(");
        boolean first = true;
        for (ClassExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeClass(writer,exp);
        }
        writer.write(")");
    }

    @Override protected void writeObjectIntersectionOf(Writer writer, ObjectIntersectionOf expression) throws java.io.IOException {
        List<ClassExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getClassSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectIntersectionOf);
        writer.write("(");
        boolean first = true;
        for (ClassExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeClass(writer,exp);
        }
        writer.write(")");
    }

    @Override protected void writeObjectOneOf(Writer writer, ObjectOneOf expression) throws java.io.IOException {
        List<IndividualExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getIndividualSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectOneOf);
        writer.write("(");
        boolean first = true;
        for (IndividualExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeIndividual(writer,exp);
        }
        writer.write(")");
    }

    @Override protected void writeObjectComplementOf(Writer writer, ObjectComplementOf expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectComplementOf);
        writer.write("(");
        writeClass(writer, expression.getClasse());
        writer.write(")");
    }

    @Override protected void writeDataAllValuesFrom(Writer writer, DataAllValuesFrom expression) throws java.io.IOException {
        List<DataPropertyExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getDataPropertySeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataAllValuesFrom);
        writer.write("(");
        boolean first = true;
        for (DataPropertyExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeDataProp(writer, exp);
        }
        writer.write(" ");
        writeDatatype(writer, expression.getDatarange());
        writer.write(")");
    }

    @Override protected void writeDataExactCardinality(Writer writer, DataExactCardinality expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataExactCardinality);
        writer.write("(");
        writeLiteral(writer, expression.getCardinality());
        writer.write(" ");
        writeDataProp(writer, expression.getDataProperty());
        if (expression.getDatarange() != null) {
            writer.write(" ");
            writeDatatype(writer, expression.getDatarange());
        }
        writer.write(")");
    }

    @Override protected void writeDataHasValue(Writer writer, DataHasValue expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataHasValue);
        writer.write("(");
        writeDataProp(writer, expression.getDataProperty());
        writer.write(" ");
        writeLiteral(writer, expression.getLiteral());
        writer.write(")");
    }

    @Override protected void writeDataMaxCardinality(Writer writer, DataMaxCardinality expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataMaxCardinality);
        writer.write("(");
        writeLiteral(writer, expression.getCardinality());
        writer.write(" ");
        writeDataProp(writer, expression.getDataProperty());
        if (expression.getDatarange() != null) {
            writer.write(" ");
            writeDatatype(writer, expression.getDatarange());
        }
        writer.write(")");
    }

    @Override protected void writeDataMinCardinality(Writer writer, DataMinCardinality expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataMinCardinality);
        writer.write("(");
        writeLiteral(writer, expression.getCardinality());
        writer.write(" ");
        writeDataProp(writer, expression.getDataProperty());
        if (expression.getDatarange() != null) {
            writer.write(" ");
            writeDatatype(writer, expression.getDatarange());
        }
        writer.write(")");
    }

    @Override protected void writeDataSomeValuesFrom(Writer writer, DataSomeValuesFrom expression) throws java.io.IOException {
        List<DataPropertyExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getDataPropertySeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataSomeValuesFrom);
        writer.write("(");
        boolean first = true;
        for (DataPropertyExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeDataProp(writer, exp);
        }
        writer.write(" ");
        writeDatatype(writer, expression.getDatarange());
        writer.write(")");
    }

    @Override protected void writeObjectAllValuesFrom(Writer writer, ObjectAllValuesFrom expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectAllValuesFrom);
        writer.write("(");
        writeObjProp(writer, expression.getObjectProperty());
        writer.write(" ");
        writeClass(writer, expression.getClasse());
        writer.write(")");
    }

    @Override protected void writeObjectExactCardinality(Writer writer, ObjectExactCardinality expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectExactCardinality);
        writer.write("(");
        writeLiteral(writer, expression.getCardinality());
        writer.write(" ");
        writeObjProp(writer, expression.getObjectProperty());
        if (expression.getClasse() != null) {
            writer.write(" ");
            writeClass(writer, expression.getClasse());
        }
        writer.write(")");
    }

    @Override protected void writeObjectHasSelf(Writer writer, ObjectHasSelf expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectHasSelf);
        writer.write("(");
        writeObjProp(writer, expression.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeObjectHasValue(Writer writer, ObjectHasValue expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectHasValue);
        writer.write("(");
        writeObjProp(writer, expression.getObjectProperty());
        writer.write(" ");
        writeIndividual(writer, expression.getIndividual());
        writer.write(")");
    }

    @Override protected void writeObjectMaxCardinality(Writer writer, ObjectMaxCardinality expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectMaxCardinality);
        writer.write("(");
        writeLiteral(writer, expression.getCardinality());
        writer.write(" ");
        writeObjProp(writer, expression.getObjectProperty());
        if (expression.getClasse() != null) {
            writer.write(" ");
            writeClass(writer, expression.getClasse());
        }
        writer.write(")");
    }

    @Override protected void writeObjectMinCardinality(Writer writer, ObjectMinCardinality expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectMinCardinality);
        writer.write("(");
        writeLiteral(writer, expression.getCardinality());
        writer.write(" ");
        writeObjProp(writer, expression.getObjectProperty());
        if (expression.getClasse() != null) {
            writer.write(" ");
            writeClass(writer, expression.getClasse());
        }
        writer.write(")");
    }

    @Override protected void writeObjectSomeValuesFrom(Writer writer, ObjectSomeValuesFrom expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectSomeValuesFrom);
        writer.write("(");
        writeObjProp(writer, expression.getObjectProperty());
        writer.write(" ");
        writeClass(writer, expression.getClasse());
        writer.write(")");
    }

    @Override protected void writeObjectProperty(Writer writer, IRI expression) throws java.io.IOException { writeEntity(writer, expression); }

    @Override protected void writeObjectInverseOf(Writer writer, ObjectInverseOf expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expObjectInverseOf);
        writer.write("(");
        writeObjProp(writer, expression.getInverse());
        writer.write(")");
    }

    @Override protected void writeDataProperty(Writer writer, IRI expression) throws java.io.IOException { writeEntity(writer, expression); }

    @Override protected void writeDatatype(Writer writer, IRI expression) throws java.io.IOException { writeEntity(writer, expression); }

    @Override protected void writeDataComplementOf(Writer writer, DataComplementOf expression) throws java.io.IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataComplementOf);
        writer.write("(");
        writeDatatype(writer, expression.getDatarange());
        writer.write(")");
    }

    @Override protected void writeDataIntersectionOf(Writer writer, DataIntersectionOf expression) throws java.io.IOException {
        List<Datarange> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getDatarangeSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataIntersectionOf);
        writer.write("(");
        boolean first = true;
        for (Datarange exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeDatatype(writer,exp);
        }
        writer.write(")");
    }

    @Override protected void writeDataOneOf(Writer writer, DataOneOf expression) throws java.io.IOException {
        List<LiteralExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getLiteralSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataOneOf);
        writer.write("(");
        boolean first = true;
        for (LiteralExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeLiteral(writer,exp);
        }
        writer.write(")");
    }

    @Override protected void writeDatatypeRestriction(Writer writer, DatatypeRestriction expression) throws java.io.IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override protected void writeDataUnionOf(Writer writer, DataUnionOf expression) throws java.io.IOException {
        List<Datarange> list = xowl.interpreter.impl.Sequences.toExpressionList(expression.getDatarangeSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.expDataUnionOf);
        writer.write("(");
        boolean first = true;
        for (Datarange exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            writeDatatype(writer,exp);
        }
        writer.write(")");
    }

    @Override protected void writeNamedIndividual(Writer writer, IRI expression) throws java.io.IOException { writeEntity(writer, expression); }

    @Override protected void writeAnonymousIndividual(Writer writer, AnonymousIndividual expression) throws java.io.IOException {
        writer.write("_:" + expression.getNodeID());
    }

    @Override protected void writeLiteral(Writer writer, Literal expression) throws java.io.IOException {
        String value = expression.getLexicalValue();
        if (expression.getMemberOf() == null) {
            writer.write("\"" + value + "\"");
        } else {
            String iri = expression.getMemberOf().getHasValue();
            xowl.interpreter.impl.JavaDatatype datatype = xowl.interpreter.impl.JavaDatatype.get(iri);
            writer.write(datatype.serialize(value));
        }
    }

    @Override protected void writeFunction(Writer writer, IRI expression) throws java.io.IOException { writeEntity(writer, expression); }

    @Override protected void writeLambda(Writer writer, Lambda expression) throws java.io.IOException { }
}
